import React, { ChangeEvent, FC, useRef, useState } from 'react'
import {
  UploadProps,
  DISPLAY_NAME_UPLOAD,
  getUploadClassNames,
  UploadFile,
  createUploadFile,
} from './config'
import Dragger from './Dragger'
import UploadList from './UploadList'
import axios from 'axios'

export const Upload: FC<UploadProps> = props => {
  const {
    action,
    defaultFileList,
    onRemove,
    beforeUpload,
    onProgress,
    onSuccess,
    onError,
    onChange,
    header,
    name,
    data,
    withCredentials,
    accept,
    multiple,
    children,
    drag,
  } = props

  const [fileList, setFileList] = useState<UploadFile[]>(defaultFileList || [])

  const uploadClasses = getUploadClassNames(props)

  const updateFileList = (
    uploadFile: UploadFile,
    updateObj: Partial<UploadFile>
  ) => {
    Object.assign(uploadFile, updateObj)
    setFileList(prevFileList => {
      return prevFileList.map(file => {
        if (file.uid === uploadFile.uid) {
          return uploadFile
        }
        return file
      })
    })
  }

  const handleChick = () => {
    if (!fileInput.current) return
    fileInput.current.click()
  }

  const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files
    if (!files) return
    uploadFiles(files)
    if (fileInput.current) {
      fileInput.current.value = ''
    }
  }

  const handleRemove = (file: UploadFile) => {
    setFileList(prevList => {
      return prevList.filter(item => item.uid !== file.uid)
    })
    onRemove && onRemove(file)
  }

  const handleBeforeUpload = (file: UploadFile) => {
    if (!beforeUpload) return Promise.resolve(file)

    const result = beforeUpload(file)
    if (result && result instanceof Promise) {
      return result
    } else if (result === true) {
      return Promise.resolve(file)
    } else {
      return Promise.reject(result)
    }
  }
  const uploadFiles = (files: FileList) => {
    const postFiles = Array.from(files).map(file => createUploadFile(file))
    postFiles.forEach(file => {
      handleBeforeUpload(file).then((processedFile: UploadFile) => {
        sentUploadRequest(processedFile)
      })
    })
  }
  const sentUploadRequest = (file: UploadFile) => {
    if (!file || !file.raw) return

    setFileList(prevList => {
      return [file, ...prevList]
    })

    const formData = new FormData()
    formData.append(name || 'file', file.raw)
    if (data) {
      Object.keys(data).forEach(key => {
        formData.append(key, data[key])
      })
    }

    axios
      .post(action, formData, {
        headers: {
          ...header,
          'Content-Type': 'multipart/form-data',
        },
        withCredentials,
        onUploadProgress: e => {
          let percentage = Math.round((e.loaded * 100) / e.total) || 0
          if (percentage < 100) {
            updateFileList(file, {
              percent: percentage,
              status: 'uploading',
            })
            onProgress && onProgress(percentage, file)
          }
        },
      })
      .then(res => {
        console.log(res)
        updateFileList(file, {
          status: 'success',
          response: res.data,
        })
        onSuccess && onSuccess(res.data, file)
      })
      .catch(err => {
        console.log(err)
        updateFileList(file, {
          status: 'error',
          error: err,
        })
        onError && onError(err, file)
      })
      .then(() => {
        onChange && onChange(file)
      })
  }

  const fileInput = useRef<HTMLInputElement>(null)
  console.log(fileList)
  return (
    <div className={uploadClasses}>
      <div
        className="upload-input"
        style={{ display: 'inline-block' }}
        onClick={handleChick}>
        {drag ? (
          <Dragger
            onFile={(files: FileList) => {
              uploadFiles(files)
            }}>
            {children}
          </Dragger>
        ) : (
          children
        )}
        <input
          className="file-input"
          style={{ display: 'none' }}
          type="file"
          onChange={handleFileChange}
          ref={fileInput}
          accept={accept}
          multiple={multiple}
        />
      </div>
      <UploadList fileList={fileList} onRemove={handleRemove}></UploadList>
    </div>
  )
}
Upload.displayName = DISPLAY_NAME_UPLOAD
Upload.defaultProps = {
  name: 'file',
}
export default Upload
